package dk.aiszone.lang.sql;

import dk.aiszone.lang.sql.interfaces.SQLChildHolder;
import dk.aiszone.lang.sql.interfaces.SQLConstraint;
import dk.aiszone.lang.sql.interfaces.SQLObject;

/*pp*/abstract class SQLList extends AbstractSQLObject implements SQLChildHolder, SQLObject {

    private SQLConstraint part1c;
    private SQLList part1l;
    private SQLList part2;

    /**
     * Constructor for the <code>SQLAnd</code> object.
     * 
     * @param arg1
     *            The first <code>SQLObject</code> contained within the <code>SQLList</code>.
     */
    /* pp */SQLList(SQLConstraint arg1) {
        this.part1c = arg1;
    }

    /**
     * Constructor for the <code>SQLAnd</code> object.
     * 
     * @param arg1
     *            The first <code>SQLList</code> contained within the <code>SQLList</code>.
     */
    /* pp */SQLList(SQLList arg1) {
        this.part1l = arg1;
    }

    @Override
    public SQLObject getChild(int index) {
        if (index == 0) {
            return (part1c != null ? part1c : part1l);
        } else if (index == 1) {
            return part2;
        }
        throw new IndexOutOfBoundsException(index + " out of bounds");
    }

    @Override
    public int getChildCount() {
        return (part2 == null ? 1 : 2);
    }

    @Override
    public SQLResult prepareSQL(SQLResult sql) {
        boolean assigned1c = isAssigned(part1c);
        boolean assigned1l = isAssigned(part1l);
        boolean assigned2 = isAssigned(part2);

        if ((assigned1c || assigned1l) && assigned2) {
            sql.append(getPrefix());
            if (assigned1c) {
                part1c.prepareSQL(sql);
            } else {
                part1l.prepareSQL(sql);
            }
            sql.append(getSeperator());
            part2.prepareSQL(sql);
            sql.append(getPostFix());
        } else if (part2 == null && (assigned1c || assigned1l)) {
            sql.append(getPrefix());
            if (assigned1c) {
                part1c.prepareSQL(sql);
            } else {
                part1l.prepareSQL(sql);
            }
            sql.append(getPostFix());
        } else {
            sql.append(this);
        }
        return sql;
    }

    @Override
    public String toPreparedStatement() {
        boolean assigned1c = isAssigned(part1c);
        boolean assigned1l = isAssigned(part1l);
        boolean assigned2 = isAssigned(part2);

        if (!assigned1c && !assigned1l && !assigned2) {
            return "";
        }

        StringBuilder sql = new StringBuilder();
        if ((assigned1c || assigned1l) && assigned2) {
            sql.append(getPrefix());
            sql.append((assigned1c ? part1c.toPreparedStatement() : part1l.toPreparedStatement()));
            sql.append(getSeperator());
            sql.append(part2.toPreparedStatement());
            sql.append(getPostFix());
        } else if ((assigned1c || assigned1l)) {
            sql.append((assigned1c ? part1c.toPreparedStatement() : part1l.toPreparedStatement()));
        } else {
            sql.append(part2.toPreparedStatement());
        }
        return sql.toString();
    }

    @Override
    public String toSQL() {
        boolean assigned1c = isAssigned(part1c);
        boolean assigned1l = isAssigned(part1l);
        boolean assigned2 = isAssigned(part2);

        if (!assigned1c && !assigned1l && !assigned2) {
            return "";
        }

        StringBuilder sql = new StringBuilder();
        if ((assigned1c || assigned1l) && assigned2) {
            sql.append(getPrefix());
            sql.append((assigned1c ? part1c.toSQL() : part1l.toSQL()));
            sql.append(getSeperator());
            sql.append(part2.toSQL());
            sql.append(getPostFix());
        } else if ((assigned1c || assigned1l)) {
            sql.append((assigned1c ? part1c.toSQL() : part1l.toSQL()));
        } else {
            sql.append(part2.toSQL());
        }
        return sql.toString();
    }

    /**
     * Retrieve the postfix character - to be postfiexe the second part of the <code>SQLList</code>.
     * 
     * @return The postfix character - default returns an empty string.
     */
    protected String getPostFix() {
        return "";
    }

    /**
     * Retrieve the prefix character - to be prefixed the first part of the <code>SQLList</code>.
     * 
     * @return The prefix character - default returns an empty string.
     */
    protected String getPrefix() {
        return "";
    }

    /**
     * Retrieve the seperator between the elements.
     * 
     * @return The seperator.
     */
    protected abstract String getSeperator();

    /* pp */boolean isAssigned() {
        return isAssigned(part1c) || isAssigned(part1l) || isAssigned(part2);
    }

    /**
     * Set the second constraint of the <code>SQLAnd</code> statement.
     * 
     * @param constraint2
     *            The second constraint contained within the <code>SQLAnd</code>.
     */
    /* pp */void setConstraint2(SQLList constraint2) {
        this.part2 = constraint2;
    }

    private boolean isAssigned(SQLConstraint constraint) {
        return (constraint == null ? false : constraint.getAssignableField().isAssigned());
    }

    private boolean isAssigned(SQLList constraint) {
        if (constraint == null) {
            return false;
        }
        return isAssigned(constraint.part1c) || isAssigned(constraint.part1l) || isAssigned(constraint.part2);
    }
}